#include "gagent_def.h"

#define   MAX_HTTPC_URL_LEN         1024

typedef int (*WEBCLIENT_CUSTOM_RESPONSE_CB)(size_t total, size_t offset, char *from, size_t from_len);


extern cloud_st *cloud;
extern lan_st *lan;


static int webclient_common(int method, const char *URI, 
                            const char * data, size_t data_sz,
                            WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
{
    struct webclient_session *session = RT_NULL;
    char *header = RT_NULL, *header_ptr;
    size_t header_sz = 0;
    int rc = WEBCLIENT_OK;
    int length = 0;
    size_t total = 0, offset = 0;
    
    rt_uint8_t *buffer = RT_NULL;

    header = (char *)rt_malloc(WEBCLIENT_HEADER_BUFSZ);
    if(RT_NULL == header)
    {
        rt_kprintf("malloc failed!\n");
        rc = -WEBCLIENT_NOMEM;
        goto __exit;
    }
    memset(header, 0, WEBCLIENT_HEADER_BUFSZ);

    header_ptr = header;
    header_ptr += rt_snprintf(header_ptr,
                            WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
                            "Content-Type: application/x-www-form-urlencoded;charset:UTF-8\r\n");
                
    if(data)
    {
        header_ptr += rt_snprintf(header_ptr, 
                                WEBCLIENT_HEADER_BUFSZ - (header_ptr - header), 
                                "Content-Length:%d\r\n", strlen(data));
    }
                            
    header_sz = header_ptr - header;
    session = webclient_open_custom(URI, method, header, header_sz, data, data_sz);
    if(RT_NULL == session)
    {
        rt_kprintf("webclient_open_custom failed!\n");
        rc = -WEBCLIENT_OK;
        goto __exit;
    }
    rt_kprintf("response:%d\n",session->response);

    buffer = (rt_uint8_t *)rt_malloc(WEBCLIENT_RESPONSE_BUFSZ);
    if(RT_NULL == buffer)
    {
        rt_kprintf("malloc failed!\n");
        rc = -WEBCLIENT_NOMEM;
        goto __exit;
    }

    if(session->chunk_sz > 0)
    {
        rt_kprintf("chunk_sz:%d\n", session->chunk_sz);
        total = session->chunk_sz;
   }
    else if(session->content_length > 0)
    {
        rt_kprintf("content_length:%d content_length_remainder:%d\n", session->content_length, session->content_length_remainder);
        total = session->content_length;
    }
    
    while(total != offset)
    {
        memset(buffer, 0, WEBCLIENT_RESPONSE_BUFSZ);
        length = webclient_read(session, buffer, WEBCLIENT_RESPONSE_BUFSZ);
        if(length <= 0)
        {
            rc = length;
            break;
        }
        
        if(webclient_custom_response_cb)
            webclient_custom_response_cb(total, offset, (char *)buffer, (int)length);

        offset += length;
    }

__exit:
    if(RT_NULL != buffer)
    {
        rt_free(buffer);
        buffer = RT_NULL;
    }

    if(RT_NULL != header)
    {
        rt_free(header);
        header = RT_NULL;
    }

    if(RT_NULL != session)
    {
        webclient_close(session);
        session = RT_NULL;
    }
    return rc; 
}

int webclient_get(const char *URI, WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
{
    return webclient_common(WEBCLIENT_GET, URI, NULL, 0, webclient_custom_response_cb);
}

int webclient_post(const char *URI, const char * data, size_t data_sz,
                            WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
{
    return webclient_common(WEBCLIENT_POST, URI, data, data_sz, webclient_custom_response_cb);
}


void StrToHex_noSpace(char *pbDest, char *pbSrc, int nLen)
{
    char h1,h2;
    char s1,s2;
    int i;

    for (i=0; i<nLen; i += 2)
    {   
        h1 = toupper(pbSrc[i]);
        if(h1 >= 'A')
            h1 = h1 - 'A' + 10;
        else
            h1 = h1 - '0';
        
        h2 = toupper(pbSrc[i + 1]);
        if(h2 >= 'A')
            h2 = h2 - 'A' + 10;
        else
            h2 = h2 - '0';

        pbDest[i / 2] = ((h1 << 4) & 0xf0) + (h2 & 0x0f);
    }   
}



int gagent_cloud_httpc_cb(size_t total, size_t offset, char *from, size_t from_len)
{
    rt_kprintf("total:%d offset:%d len:%d\n", total, offset, from_len);
    rt_kprintf("buf:%s\n", from);
    
 //   cloud_st *cloud = get_gagent_cloud_info();

    rt_memset(cloud->recv_buf, 0, sizeof(cloud->recv_buf));
    rt_memcpy(cloud->recv_buf, from, from_len);
    cloud->recv_len = from_len;

    return RT_EOK;
}

int gagent_cloud_register(void)
{
    int rc = RT_EOK;
    rt_uint8_t *url = RT_NULL;
    rt_uint8_t *url_ptr;
    rt_uint8_t *content = RT_NULL;

    rt_uint8_t pksecHex[48];
    rt_uint8_t encryptData[128], encryptDataStr[256], decryptData[256];

    int len;
    rt_uint8_t i;
    rt_uint8_t byteData[4];
    
    content = (rt_uint8_t *)rt_malloc(256);
    if(RT_NULL == content)
    {
        rc = -RT_ENOMEM;
        goto __exit;
    }

    //data
    memset(content, 0, 256);
    rt_snprintf((char *)content, 256, "mac=%s&passcode=%s&type=%s", cloud->con->mac, cloud->con->passcode, "normal");

    aesInit();
    StrToHex_noSpace((char *)pksecHex, cloud->con->pk_secret, strlen(cloud->con->pk_secret));

    rt_kprintf("content:%s, pk_secret:%s\n", content, cloud->con->pk_secret);
    len = (int)aesECB128Encrypt(content, encryptData, pksecHex, strlen((const char *)content));
    if(len > 0)
    {
        memset(encryptDataStr, 0, sizeof(encryptDataStr));
        for(i = 0; i < len; i ++)
        {
            memset(byteData, 0, sizeof(byteData));
            snprintf(byteData, 4, "%02x", encryptData[i]);
            memcpy(&encryptDataStr[i * 2], byteData, strlen((const char *)byteData));
        }
    }
    aesDestroy();

    memset(content, 0, 256);
    rt_snprintf(content, 256, "data=%s", encryptDataStr);

    rt_kprintf("content:%s\n", content);

    url = (rt_uint8_t *)rt_malloc(MAX_HTTPC_URL_LEN);
    if(RT_NULL == url)
    {
        rc = -RT_ENOMEM;
        return rc;
    }

    url_ptr = url;
    memset(url, 0, MAX_HTTPC_URL_LEN);
    
    //url
    url_ptr += rt_snprintf(url_ptr, MAX_HTTPC_URL_LEN - (url_ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
    url_ptr += rt_snprintf(url_ptr, MAX_HTTPC_URL_LEN - (url_ptr - url), "/dev/%s/device", cloud->con->pk);
    
    rt_kprintf("url:%s\n", url);
    rc = webclient_post((const char *)url, (const char *)content, strlen(content), gagent_cloud_httpc_cb);
    if(rc != RT_EOK)
    {
        rt_kprintf("weblient_post failed!\n");
        goto __exit;
    }
    
    aesInit();
    rt_memset(decryptData, 0, sizeof(decryptData));
    StrToHex_noSpace((char *)encryptDataStr, (char *)cloud->recv_buf, cloud->recv_len);
    len = aesECB128Decrypt(encryptDataStr, decryptData, pksecHex, cloud->recv_len / 2);

    rt_kprintf("%s\n", decryptData);
    aesDestroy();

    rt_memcpy(cloud->con->did, decryptData + strlen("did="), DID_LENGTH);
    
__exit:
    if(RT_NULL != url)
        rt_free(url);

    if(RT_NULL != content)
        rt_free(content);

    return rc;
}

int gagent_cloud_provision(void)
{
//    cloud_st *cloud = get_gagent_cloud_info();

    int rc = RT_EOK;
    rt_uint8_t *url = RT_NULL;
    rt_uint8_t *url_ptr;
    rt_uint8_t *content = RT_NULL;

    rt_uint8_t pksecHex[48];
    rt_uint8_t encryptData[128], encryptDataStr[256], decryptData[256];

    int len;
    rt_uint8_t i;
    rt_uint8_t byteData[4];

    rt_uint8_t *ptr = RT_NULL, *ptr_tail = RT_NULL;
    
    content = (rt_uint8_t *)rt_malloc(256);
    if(RT_NULL == content)
    {
        rc = -RT_ENOMEM;
        goto __exit;
    }

    //data
    memset(content, 0, 256);
    aesInit();
    StrToHex_noSpace((char *)pksecHex, cloud->con->pk_secret, strlen(cloud->con->pk_secret));

    rt_kprintf("content:%s, pk_secret:%s\n", cloud->con->did, cloud->con->pk_secret);
    len = (int)aesECB128Encrypt(cloud->con->did, encryptData, pksecHex, strlen((const char *)cloud->con->did));
    if(len > 0)
    {
        memset(encryptDataStr, 0, sizeof(encryptDataStr));
        for(i = 0; i < len; i ++)
        {
            memset(byteData, 0, sizeof(byteData));
            snprintf(byteData, 4, "%02x", encryptData[i]);
            memcpy(&encryptDataStr[i * 2], byteData, strlen((const char *)byteData));
        }
    }
    aesDestroy();


    rt_kprintf("encryptDataStr:%s\n", encryptDataStr);

    url = (rt_uint8_t *)rt_malloc(MAX_HTTPC_URL_LEN);
    if(RT_NULL == url)
    {
        rc = -RT_ENOMEM;
        return rc;
    }

    url_ptr = url;
    memset(url, 0, MAX_HTTPC_URL_LEN);
    
    //url
    url_ptr += rt_snprintf(url_ptr, MAX_HTTPC_URL_LEN - (url_ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
    url_ptr += rt_snprintf(url_ptr, MAX_HTTPC_URL_LEN - (url_ptr - url), "/dev/%s/device?", cloud->con->pk);
    url_ptr += rt_snprintf(url_ptr, MAX_HTTPC_URL_LEN - (url_ptr - url), "did=%s", encryptDataStr);
    rt_kprintf("url:%s\n", url);
    
    rc = webclient_get((const char *)url, gagent_cloud_httpc_cb);
    if(rc != RT_EOK)
    {
        rt_kprintf("weblient_post failed!\n");
        goto __exit;
    }
    
    aesInit();
    rt_memset(decryptData, 0, sizeof(decryptData));
    StrToHex_noSpace((char *)encryptDataStr, (char *)cloud->recv_buf, cloud->recv_len);
    len = aesECB128Decrypt(encryptDataStr, decryptData, pksecHex, cloud->recv_len / 2);

    aesDestroy();
    rt_kprintf("%s\n", decryptData);

    //mqtt_server
    rt_memset(cloud->mqtt_server, 0, sizeof(cloud->mqtt_server));
    ptr = strstr(decryptData, "host=");
    if(ptr > 0)
    {
        ptr += strlen("host=");
        ptr_tail = strchr(ptr, '&');
        if(ptr_tail > 0)
            rt_memcpy(cloud->mqtt_server, ptr, (ptr_tail - ptr));
//        else
//            rt_memcpy(cloud->mqtt_server, G_M2M_DOMAIN, sizeof(G_M2M_DOMAIN));
    }
//    else
//        rt_memcpy(cloud->mqtt_server, G_M2M_DOMAIN, sizeof(G_M2M_DOMAIN));

    //mqtt_port
    cloud->mqtt_port = 0;
    ptr = strstr(decryptData, "port=");
    if(ptr > 0)
    {
        ptr += strlen("port=");

        ptr_tail = strchr(ptr, '&');
        if(ptr_tail > 0)
        {
            *ptr_tail = '\0';
            cloud->mqtt_port = atoi(ptr);
        }
//        else
//            cloud->mqtt_port = atoi(G_M2M_PORT);
    }
//    else
//        cloud->mqtt_port = atoi(G_M2M_PORT);

    rt_kprintf("mqtt_server:%s port:%d\n", cloud->mqtt_server, cloud->mqtt_port);

__exit:
    if(RT_NULL != url)
        rt_free(url);

    if(RT_NULL != content)
        rt_free(content);

    return rc;
}

